﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using  PI_CS_Library.Virtual_Network_Information_Model;
using TransportLayer;

namespace  PI_CS_Library.PicsNetwork_Information_Model
{
    public class PicsNetwork 
    {
        Dictionary<int, VirtualNetwork> _hostedNetworkList;
        Dictionary<int, PicsLink> _linkResourceList;
        Dictionary<int, PicsMatrix> _matrixResourceList;
        Dictionary<int, PicsVirtualLink> _virtualLinkList;
        Dictionary<int, int> _linkMappingList;

        public PicsNetwork()
        {
            _matrixResourceList = new Dictionary<int, PicsMatrix>();
            _linkResourceList = new Dictionary<int, PicsLink>();
            _hostedNetworkList = new Dictionary<int, VirtualNetwork>();
            _virtualLinkList = new Dictionary<int, PicsVirtualLink>();
            _linkMappingList = new Dictionary<int, int>();

        }

        public PicsMatrix AddNewMatrix(int _id, string _name, string _type, float _x, float _y, MatrixParameters _parameters)
        {
            PicsMatrix _newMatrix = new PicsMatrix(_id, _name, _type, _x, _y, _parameters);

            _matrixResourceList.Add(_id, _newMatrix);

            return _newMatrix;
        }

        public PicsLink AddNewLink(int _id, PicsMatrix _srcMatrix, PicsMatrix _sinkMatrix, int _srcPort, int _dstPort, LinkParameters _parameters)
        {
            bool _exist = false;



            if (!_exist)
            {
                PicsLink newLink = new PicsLink(_id, _srcMatrix, _sinkMatrix, _srcPort, _dstPort, _parameters);
                _matrixResourceList[_srcMatrix.Id.Number]._outgoingLinkList.Add(newLink.Id.Number, newLink);
                _matrixResourceList[_sinkMatrix.Id.Number]._incomingLinkList.Add(newLink.Id.Number, newLink);
                _linkResourceList.Add(newLink.Id.Number, newLink);

                return newLink;
            }

            return null;
        }

        public void RemoveMatrix(int _matrixId, PicsNetworkController _nc, GUIDelegate _gui, bool _refresh)
        {
            PicsMatrix _oldMatrix = _matrixResourceList[_matrixId];

            List<int> _linksToRemove = new List<int>();

            _matrixResourceList.Remove(_matrixId);

            _nc.ManagerEngine.Nodes[_matrixId].KillProcess();

            _nc.ManagerEngine.Nodes.Remove(_matrixId);

            foreach (int _inLinkId in _oldMatrix.IncomingLinkList.Keys)
                _linksToRemove.Add(_inLinkId);

            foreach (int _outLinkId in _oldMatrix.OutgoingLinkList.Keys)
                _linksToRemove.Add(_outLinkId);

            foreach(int _linkId in _linksToRemove)
                RemoveLink(_linkId, _nc, _gui, false, _matrixId);

            if(_refresh)
                _gui(this, new GUIArgs("delMatrixOK#" + _oldMatrix.Name + "#" + "refresh"));
            else
                _gui(this, new GUIArgs("delMatrixOK#" + _oldMatrix.Name + "#" + "no_refresh"));
        }

        public void RemoveLink(int _linkId, PicsNetworkController _nc, GUIDelegate _gui, bool _refresh, int _initMatrixId)
        {
            PicsVirtualLink _picsVLink;
            int _picsVLinkId, _matrixId, _sourceId, _sinkId, _vnId, _capacity, _connId;
            Matrix _currMatrix;
            string[] param;

            Dictionary<int, Virtual_Network_Information_Model.Link> _linkList = new Dictionary<int, Virtual_Network_Information_Model.Link>();

            Dictionary<int, Dictionary<int, PicsLink>> _allLinkList = new Dictionary<int, Dictionary<int, PicsLink>>();

            Dictionary<int, LinkConnection> _oldLinkConnections = new Dictionary<int, LinkConnection>();

            Dictionary<string, List<Matrix>> _matrixLists = new Dictionary<string, List<Matrix>>();

            Dictionary<int, PI_CS_Library.Virtual_Network_Information_Model.Link> _linksToReset =
                new Dictionary<int,Virtual_Network_Information_Model.Link>(_linkResourceList[_linkId].HostedLinkList);

            foreach (PI_CS_Library.Virtual_Network_Information_Model.Link l in _linksToReset.Values)
            {
                _picsVLinkId = _linkMappingList[l.Id.Number];
                _picsVLink = _virtualLinkList[_picsVLinkId];

                _vnId = _picsVLink.vnId;

                _oldLinkConnections = new Dictionary<int,LinkConnection>(l.LinkConnectionsList);

                foreach (LinkConnection lc in _oldLinkConnections.Values)
                {
                    NetworkConnection _oldConnection = _hostedNetworkList[_vnId].GetNetworkConnection(lc.NetworkConnectionId.Number);
                   
                    List<Matrix> _mList = new List<Matrix>();

                    for (int i = 1; i < _oldConnection.MatrixConnectionsList.Count-1; i++)
                    {
                        _matrixId = (_oldConnection.MatrixConnectionsList.ElementAt(i).Value as MatrixConnection<CTP, CTP>).MatrixId.Number;
                        _currMatrix = _hostedNetworkList[_vnId].GetMatrix(_matrixId);
                        _mList.Add(_currMatrix);
                    }

                    _matrixId = (_oldConnection.MatrixConnectionsList.First().Value as MatrixConnection<NwTTP, CTP>).MatrixId.Number;
                    _currMatrix = _hostedNetworkList[_vnId].GetMatrix(_matrixId);
                    _mList.Add(_currMatrix);
                    _matrixId = (_oldConnection.MatrixConnectionsList.Last().Value as MatrixConnection<CTP, NwTTP>).MatrixId.Number;
                    _currMatrix = _hostedNetworkList[_vnId].GetMatrix(_matrixId);
                    _mList.Add(_currMatrix);


                    _sourceId = _oldConnection.SrcPoint.Id.Number;
                    _sinkId = _oldConnection.SinkPoint.Id.Number;

                    _matrixLists.Add(_vnId + "#" + _oldConnection.Id.Number + "#" + _oldConnection.Capacity + "#" + _sourceId + "#" + _sinkId, _mList);

                    _nc.SNCC.TearDownNetworkConnection(_vnId, lc.NetworkConnectionId.Number);
                }
            }

            PicsMatrix _src = LinkResourceList[_linkId].SrcMatrix;
            PicsMatrix _dst = LinkResourceList[_linkId].SinkMatrix;

            _src._outgoingLinkList.Remove(_linkId);
            _dst._incomingLinkList.Remove(_linkId);

            _linkResourceList.Remove(_linkId);

            _nc.ManagerEngine.Links.Remove(_linkId);

            if (_src._incomingLinkList.Count == 0 && _src._outgoingLinkList.Count == 0)
                if(_src.Id.Number != _initMatrixId)
                    RemoveMatrix(_src.Id.Number, _nc, _gui, false);
            if(_dst._incomingLinkList.Count == 0 && _dst._outgoingLinkList.Count == 0)
                if(_dst.Id.Number != _initMatrixId)
                    RemoveMatrix(_dst.Id.Number, _nc, _gui, false);
            
            if(_refresh)
                _gui(this, new GUIArgs("delLinkOK#" + _src.Name + "#" + _dst.Name + "#" + _linkId + "#" + "refresh"));
            else
                _gui(this, new GUIArgs("delLinkOK#" + _src.Name + "#" + _dst.Name + "#" + _linkId + "#" + "no_refresh"));

            foreach (PI_CS_Library.Virtual_Network_Information_Model.Link l in _linksToReset.Values)
            {
                _picsVLinkId = _linkMappingList[l.Id.Number];
                _picsVLink = _virtualLinkList[_picsVLinkId];

                try
                {
                    _nc.AddVirtualLink(_picsVLink);
                }
                catch (ResourceException)
                {
                    _gui(this, new GUIArgs("linkDown#" + _picsVLinkId));
                    continue;
                }

                _nc.RemoveVirtualLink(_picsVLink.vnId, l.Id.Number, false);
            }

            foreach (string _line in _matrixLists.Keys)
            {
                param = _line.Split('#');
                _vnId = Int32.Parse(param[0]);
                _connId = Int32.Parse(param[1]);
                _capacity = Int32.Parse(param[2]);
                _sourceId = Int32.Parse(param[3]);
                _sinkId = Int32.Parse(param[4]);

                _linkList = _nc.Network.GetVirtualNetwork(_vnId).GetLinkListFromMatrixList(_matrixLists[_line], _capacity);

                NwTTP _source = _nc.Network.GetVirtualNetwork(_vnId).GetNwTTP(_sourceId);
                NwTTP _sink = _nc.Network.GetVirtualNetwork(_vnId).GetNwTTP(_sinkId);

                _allLinkList = _nc.MapVirtualLinks(_linkList);
                _nc.SNCC.SetUpNetworkConnection(_connId, _vnId, _allLinkList, _source, _sink, _capacity);
            }

        }

        public int GetHostedMatrixId(int _picsNodeId, int _vnId)
        {
            foreach(Matrix _node in _matrixResourceList[_picsNodeId].HostedMatrixList.Values)
            {
                if (_hostedNetworkList[_vnId].MatrixList.ContainsKey(_node.Id.Number))
                    return _node.Id.Number;
            }

            return -1;
        }

        public PicsMatrix GetMatrix(int _matrixId)
        {
            return _matrixResourceList[_matrixId];
        }

        public void AddMatrix(PicsMatrix _newMatrix)
        {
            _matrixResourceList.Add(_newMatrix.Id.Number, _newMatrix);
        }

        public string GetMatrixList()
        {
            string result = null;

            foreach (PicsMatrix _matrix in MatrixResourceList.Values)
            {
                if(_matrix.Parameters.Accessible)
                result += _matrix.Id.Number + ":" + _matrix.Name + ":" + _matrix.Type + ":" 
                    + _matrix.PositionX + ":" + _matrix.PositionY + "#";
            }

            return result;
        }

        public TransportLayer.Network GetTransportRepresentation()
        {
            TransportLayer.Network _network = new TransportLayer.Network();

            foreach (PicsMatrix _node in MatrixResourceList.Values)
            {
                TransportLayer.Node _newTransportNode = _node.GetTransportRepresentation();

                _network.Nodes.Add(_newTransportNode);
            }

            foreach (PicsLink _link in LinkResourceList.Values)
            {
                TransportLayer.Link _newTransportLink = _link.GetTransportRepresentation();

                _network.Links.Add(_newTransportLink);
            }

            return _network;
        }

        public PicsLink GetLink(int _linkId)
        {
            return _linkResourceList[_linkId];
        }

        public void AddLink(PicsLink _newLink)
        {
            _linkResourceList.Add(_newLink.Id.Number, _newLink);
        }

        public int GetLinkId(string _srcName, string _dstName)
        {
            foreach (PicsLink l in _linkResourceList.Values)
            {
                if (l.SrcMatrix.Name == _srcName && l.SinkMatrix.Name == _dstName)
                    return l.Id.Number;
            }

            return -1;
        }

        public int GetMatrixId(string _matrixName)
        {
            foreach (PicsMatrix p in _matrixResourceList.Values)
            {
                if (p.Name == _matrixName)
                    return p.Id.Number;
            }

            return -1;
        }

        public Dictionary<int, PicsLink> LinkResourceList
        {
            get { return _linkResourceList; }
            set { _linkResourceList = value; }
        }

        public Dictionary<int, PicsVirtualLink> VirtualLinkList
        {
            get { return _virtualLinkList; }
            set { _virtualLinkList = value; }
        }

        public Dictionary<int, VirtualNetwork> HostedNetworkList
        {
            get { return _hostedNetworkList; }
            set { _hostedNetworkList = value; }
        }

        public Dictionary<int, int> LinkMappingList
        {
            get { return _linkMappingList; }
            set { _linkMappingList = value; }
        }

        public Dictionary<int, PicsMatrix> MatrixResourceList
        {
            get { return _matrixResourceList; }
            set { _matrixResourceList = value; }
        }

        public PicsVirtualLink GetVirtualLink(int _virtualLinkId)
        {
            return _virtualLinkList[_virtualLinkId];
        }

        public void AddVirtualLink(PicsVirtualLink _newVirtualLink)
        {
            _virtualLinkList.Add(_newVirtualLink.Id.Number, _newVirtualLink);
        }

        public VirtualNetwork GetVirtualNetwork(int _virtualNetworkId)
        {
            return _hostedNetworkList[_virtualNetworkId];
        }

        public void AddVirtualNetwork(VirtualNetwork _newVirtualNetwork)
        {
            _hostedNetworkList.Add(_newVirtualNetwork.Id.Number, _newVirtualNetwork);
        }

        public void RemoveVirtualNetwork(int _vnId)
        {
            _hostedNetworkList.Remove(_vnId);
        }
    }
}
